package nl.cypherpunk.statefuzzer.rtsp;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;

public class RTSPCrash {

    public static void main(String[] args) throws Exception {
        //paragrams parse
        //args[0] : aflnet
        //args[1] : port(8554)
        //args[2] : seed directory path
        //args[3] : target command
        //args[4] : client or server
        if (args.length >= 3) {
            RTSPTestService rtsp = new RTSPTestService();
            //tls.setOutput(true);
            rtsp.setOutputDir(args[0]);
            rtsp.setTarget(args[4]);
            rtsp.setHost("127.0.0.1");
            rtsp.setPort(Integer.valueOf(args[1]));
            rtsp.setCommand(args[3]);
            rtsp.setReceiveMessagesTimeout(100);
            rtsp.setConsoleOutput(false);
            rtsp.setRestartTarget(true);
            rtsp.setRedirectFile("output.log");
            rtsp.start();
            int uniqueCrashes = 0;
            File file = new File(args[2]);
            File[] tempList = file.listFiles();
            List fileList = Arrays.asList(tempList);
            Collections.sort(fileList, new Comparator<File>() {
                @Override
                public int compare(File o1, File o2) {
                    if (o1.isDirectory() && o2.isFile())
                        return -1;
                    if (o1.isFile() && o2.isDirectory())
                        return 1;
                    return o1.getName().compareTo(o2.getName());
                }
            });
            int totalNum = 0;
            for (File file1 : tempList) {
                File temp = new File(file1.getPath());
                totalNum++;
                try {
                    FileInputStream fileIn = new FileInputStream(temp);
                    //DataInputStream in = new DataInputStream(fileIn);
                    System.out.println(file1.getName());
                    // 使用缓存区读入对象效率更快
                    if(args[0].equals("aflnet"))
                    {
                        byte[] len = new byte[1024];
                        int length;
                        rtsp.reset();
                        while (fileIn.read(len,0,4) != -1) {
                            length = byteArrayToInt(len);
                            byte[] bys = new byte[length];
                            fileIn.read(bys, 0, length);
                            try {
                                String output = rtsp.sendFuzzingMessage(bys);
                                if (output.contains("Closed"))
                                    break;
                            } catch (Exception e) {
                                System.out.println(e);
                            }
                        }
                    }
                    else
                    {
                        int length;
                        rtsp.reset();
                        int size = fileIn.available();
                        byte[] bys = new byte[size];
                        if (fileIn.read(bys,0,size) != -1) {
                            try {
                                String output = rtsp.sendFuzzingMessage(bys);
                            } catch (Exception e) {
                                System.out.println(e);
                            }
                        }
                    }

                    fileIn.close();
                } catch (Exception e) {
                    System.out.println(e);
                }

                int coverage = rtsp.getCoverage();
                if(coverage==1)
                {
                    uniqueCrashes++;
                    System.out.println(file1.getName());
                }
                rtsp.closeSocket();
                rtsp.close();
            }
            System.out.println("Unique Crashes: "+uniqueCrashes);
            return;
        }
    }
        public static int byteArrayToInt ( byte[] bytes){
            int value = 0;
            for (int i = 0; i < 4; i++) {
                int shift = i * 8;
                value += (bytes[i] & 0xFF) << shift;
            }
            return value;
        }
}
